
#define BOOST_SPIRIT_DEBUG        // define this for debug output
#include <boost/spirit/core.hpp>
#include <boost/spirit/symbols/symbols.hpp>
#include <boost/spirit/utility/distinct.hpp>

#include <iostream>
#include <string>
#include <algorithm>

////////////////////////////////////////////////////////////////////////////
using namespace std;
using namespace boost::spirit;

// keyword_p for C++
// (for basic usage instead of std_p)
const distinct_parser<> keyword_p("0-9a-zA-Z_");

// keyword_d for C++
// (for mor intricate usage, for example together with symbol tables)
const distinct_directive<> keyword_d("0-9a-zA-Z_");




////////////////////////////////////////////////////////////////////////////
//
//  Semantic actions
//
////////////////////////////////////////////////////////////////////////////

struct decl_qf
{
    template<typename IT>
    void operator()(IT f, IT l) const
    {
	cout << "Quantifier: ";
        std::copy(f, l, std::ostream_iterator<char>(cout, ""));
	cout<< endl;
    }
};


struct redecl_var
{
    void operator()(double& /*n*/) const
    {
        cout << "Warning. You are attempting to re-declare a var." << endl;
    }
};

struct decl_num
{
    void operator()(const double& n) const
    {
        cout << "Number: " << n << endl;
    }
};


struct decl_conj 
{
    void operator()(char const *, char const *)const{
	cout << "TODO: Declare conj" << endl;
    }
};

struct decl_disj {
    void operator()(char const*, char const*)const{
	cout << "TODO: Declare disj" << endl;
    }
};

struct decl_not {
    void operator()(char const*, char const*)const{
	cout << "TODO: Declare disj" << endl;
    }
};

struct decl_op {
    decl_op(string op):op_(op){}
    void operator()(char const*, char const*) const{
	cout << "\nTODO: Declare op:" << op_ << endl;
    }
    std::string op_;
};

struct decl_var {
    template<typename IT>
    void operator()(IT f, IT l) const
    {
	cout << "\nVar: ";
        std::copy(f, l, std::ostream_iterator<char>(cout, ""));
	cout<< endl;
    }
};



struct decl_equs {
    decl_equs(string op):op_(op){}
    void operator()(char const*, char const*) const{
	cout << "TODO: Declare equs:" << op_ << endl;
    }
    std::string op_;
};

template<typename ContextT>
struct parser_context_linker: public ContextT{};

////////////////////////////////////////////////////////////////////////////
//
// The grammar 
//  
////////////////////////////////////////////////////////////////////////////


struct calculator : public grammar<calculator>
{
    template <typename ScannerT>
    struct definition
    {
	definition(calculator const& self)
        {
	 quantifier =
                (keyword_p("Forall")[decl_qf()] | keyword_p("Exists")[decl_qf()])  >> 
		( 
		       var_list
		| '(' >> var_list >> ')'
		)
                ;
	var_list = var_decl >> *(',' >> var_decl);
	//var_list = list_p(var_decl, ch_p(','));
	var_decl =
                lexeme_d
                [
                    ((alpha_p >> *(alnum_p | '_'))
                        - vars[redecl_var()] )[vars.add]
                ]
                ;
	 logic
                = lterm 
		    >> *( ('&' >> lterm)[decl_conj()]
                    |	 ('|' >> lterm)[decl_disj()]
                    //|	 ('~'>>'('>>lterm >>')')[decl_not()]
		    )
                ;
	lterm 
		= *(quantifier) 
		>> (
		'('>> logic>> ')'
		|    equs
		)
		;
	equs =  math >>
		(
	     	    ( '>' >> math)[decl_equs(">")]
	     	|   ( '<' >> math)[decl_equs("<")]
		|   ( "<=" >> math)[decl_equs("<=")]
		|   ( ">=" >> math)[decl_equs(">=")]
		|   ( '=' >> math)[decl_equs("=")]
		)
		;
	math = 
		mexpr
		>> *( ('+' >> mexpr)[decl_op("+")]
		|     ('-' >> mexpr)[decl_op("-")]
		)
		;
	mexpr =
		factor
		>>*(	('*'>>factor)[decl_op("*")]
		|	('/'>>factor)[decl_op("/")]
		)
		;
	factor =
			'(' >> math >> ')'
                |	real_p[decl_num()]
		|	lexeme_d [
			    (alpha_p >> *(alnum_p | '_') ) [decl_var()] 
			]
                |	('-' >> factor)[decl_op("-")]
                ;
		 BOOST_SPIRIT_DEBUG_RULE(logic);
		 BOOST_SPIRIT_DEBUG_RULE(lterm);
		 BOOST_SPIRIT_DEBUG_RULE(var_list);
		 BOOST_SPIRIT_DEBUG_RULE(var_decl);
		 BOOST_SPIRIT_DEBUG_RULE(quantifier);
		 BOOST_SPIRIT_DEBUG_RULE(equs);
		 BOOST_SPIRIT_DEBUG_RULE(math);
		 BOOST_SPIRIT_DEBUG_RULE(mexpr);
		 BOOST_SPIRIT_DEBUG_RULE(factor);
	}
    
    //rule<ScannerT, parser_context_linker<parser_context> > 
    //rule<ScannerT, parser_context<> > 
     rule<ScannerT> 
	factor, mexpr, math, equs,
        quantifier, var_decl, var_list, lterm, logic;
    
    symbols<double>     vars;

    rule<ScannerT> const& start() const { return logic; }
    };
};



////////////////////////////////////////////////////////////////////////////
//
//  Main program
//
////////////////////////////////////////////////////////////////////////////
int
main()
{
    cout << "/////////////////////////////////////////////////////////\n\n";
    cout << "\t\tExpression parser...\n\n";
    cout << "/////////////////////////////////////////////////////////\n\n";
    cout << "Type an expression...or [q or Q] to quit\n\n";

    calculator calc;    //  Our parser

    string str;
    while (getline(cin, str))
    {
        if (str.empty() || str[0] == 'q' || str[0] == 'Q')
            break;

        parse_info<> info = parse(str.c_str(), calc, space_p);

        if (info.full)
        {
            cout << "-------------------------\n";
            cout << "Parsing succeeded\n";
            cout << "-------------------------\n";
        }
        else
        {
            cout << "-------------------------\n";
            cout << "Parsing failed\n";
            cout << "stopped at: \": " << info.stop << "\"\n";
            cout << "-------------------------\n";
        }
    }

    cout << "Bye... :-) \n\n";
    return 0;
}
